<?php

namespace Managers;

class Users extends BaseManager
{
    const TABLE = '\Catalog\Users';
    const SALT = '*s&sad(76s!23XZm0sds(123';

    const MAX_AVATAR_WIDTH = 150;
    const MAX_AVATAR_HEIGHT = 150;

    protected $__table = self::TABLE;

    /**
     * @param array $params
     * @return \Catalog\Users
     */
    public function add(array $params)
    {
        $baseMoney = \Zend_Registry::get('config')->resources->frontController->baseMoney;

        $user = new \Catalog\Users();
        $user->setEmail($params['email']);
        $user->setLastName($params['lastname']);
        $user->setName($params['name']);
        $user->setPassword(md5($params['password']));
        $user->setIsAdmin(0);
        $user->setMailSent(false);
        $user->setMoney($baseMoney);
        $user->setPostal($params['postal']);
        $user->setBirthday(\DateTime::createFromFormat('Y-m-d', $params['birthday']));
        $gender = $this->_em->getReference(Genders::TABLE, $params['gender']);
        $user->setGender($gender);
        $user->setNick($params['nick']);

        if (!empty($params['token'])) {
            $inviteManager = new \Managers\Invites();
            try {
                $invite = $inviteManager->getByToken($params['token']);

                $friendMoney = \Zend_Registry::get('config')->resources->frontController->friendMoney;
                $parentUser = $this->_em->find(self::TABLE, $invite['user']['id']);

                $parentUser->setMoney($parentUser->getMoney() + $friendMoney);

                $this->_em->persist($parentUser);
                $user->setParent($parentUser);
                
            } catch (Exception $e) {

            }
        }

        $this->_em->persist($user);
        $this->_em->flush();
        return $user;
    }

    public
    function auth($email, $password)
    {
        $em = $this->_em;

        $authAdapter = new \Lib_Auth_Adapter_Doctrine();
        $authAdapter->setConnection($em);
        $authAdapter->setTableName(self::TABLE);

        $validator = new \Zend_Validate_EmailAddress();
        $identity = 'nick';
        if ($validator->isValid($email)) {
            $identity = 'email';
        }

        $authAdapter->setIdentityColumn($identity);
        $authAdapter->setCredentialColumn('password');

        $authAdapter->setIdentity($email);
        $authAdapter->setCredential($password);

        $auth = \Zend_Auth::getInstance();

        $result = $auth->authenticate($authAdapter);

        if ($result->isValid()) {
            $data = $authAdapter->getResultRowObject(null, 'password');
            $auth->getStorage()->write($data);
        }

        return $result->isValid();
    }

    public
    function getById($id)
    {
        $res = $this->_em->createQueryBuilder()
                ->select('u,g')
                ->from($this->__table, 'u')
                ->join('u.gender', 'g')
                ->where('u.id = :id')
                ->setParameter('id', $id)
                ->getQuery()
                ->getArrayResult();

        if (count($res)) {
            $user = $res[0];
            unset($user['password']);
            return $user;
        }
        return false;
    }

    public
    function getList()
    {
        $res = $this->_em->createQueryBuilder()
                ->select('partial u.{id, email, name, lastName, money}')
                ->from($this->__table, 'u')
                ->getQuery()
                ->getArrayResult();
        return $res;
    }

    function getNotDelivered()
    {
        $res = $this->_em->createQueryBuilder()
                ->select('u')
                ->from($this->__table, 'u')
                ->where('u.mailSent = 0')
                ->getQuery()
                ->getArrayResult();
        return $res;
    }

    function setMailSent($id, $status = true)
    {
        $res = $this->_em->find($this->__table, $id);
        if ($res) {
            $res->setMailSent($status);
            $this->_em->persist($res);
            $this->_em->flush();
        }
        return $res;
    }

    /**
     * Обнуляет флаг отправки сообщения.
     * @return void
     */
    function resetMailSent()
    {
        $res = $this->_em->getRepository($this->__table)->findAll();

        foreach ($res as $user) {
            $user->setMailSent(false);
            $this->_em->persist($user);
        }

        $this->_em->flush();
    }

    function getNotDeliveredByMap($map_id)
    {
        $res = $this->_em->createQueryBuilder()
                ->select('partial u.{id,email}')
                ->from($this->__table, 'u')
                ->where('u.map = :map')->setParameter('map', $map_id)
                ->andWhere('u.mailSent = 0')
                ->getQuery()
                ->getArrayResult();
        return $res;
    }

    /**
     * Отправляет инвайт.
     * @param $email
     * @param $userId
     * @return void
     */
    public
    function doSendInvite($email, $userId)
    {

        $user = $this->_em->find(self::TABLE, $userId);

        if (!$user) {
            throw new \Exception('Such user does not exist.');
        }

        $secretWord = $this->getSecretWord();
        $word = $user->getId() . '|' . $secretWord;

        $baseUrl = \Zend_Registry::get('config')->resources->frontController->baseUrl;

        $message = <<<_END
        You have been invited to <a href="{$baseUrl}">TreasureAce.ca</a> by {$user->getName()} {$user->getLastName()}.
        
_END;

        Mail::sendEmail($message, $email, 'Friend invite');
    }

    /**
     * Возвращает секретное слово.
     * @return string
     */
    public static function getSecretWord()
    {
        $args = func_get_args();
        $word = '';
        foreach ($args as $arg) {
            $word .= $arg;
        }
        return md5($word . self::SALT);
    }

    public function isValid($id, $word)
    {
        $res = $this->_em->createQueryBuilder()
                ->select('u')
                ->from(self::TABLE, 'u')
                ->where('u.id = :id')
                ->setParameter('id', $id)
                ->getQuery()
                ->getArrayResult();

        if (count($res)) {
            $user = $res[0];
            $credential = $this->getSecretWord($user['name'],
                                               $user['email'],
                                               $user['password']);
            if ($word == $credential) {
                return $user;
            }


        }
        return false;
    }

    public function doLogin($params)
    {
        if (array_key_exists('password', $params)) {
            unset($params['password']);
        }

        $auth = \Zend_Auth::getInstance();
        $auth->getStorage()->write((object)$params);
    }

    public function updatePassword($user_id, array $params)
    {
        $user = $this->_em->find(self::TABLE, $user_id);

        if (!isset($user)) {
            throw new \Exception('User does not exist.');
        }

        if (md5($params['oldPassword']) != $user->getPassword()) {
            throw new \Exception('Invalid current password.');
        }

        $user->setPassword(md5($params['newPassword']));
        $this->_em->persist($user);
        $this->_em->flush();

        return $user;
    }

    public function updatePersonal($user_id, array $params)
    {
        $user = $this->_em->find(self::TABLE, $user_id);

        if (!isset($user)) {
            throw new \Exception('User does not exist.');
        }

        $user->setPostal($params['postal']);
        $user->setBirthday(\DateTime::createFromFormat('Y-m-d', $params['birthday']));
        $user->setName($params['name']);
        $user->setLastName($params['lastName']);

        $this->_em->persist($user);
        $this->_em->flush();
        return $user;
    }

    public function updateAvatar($user_id, $avatar)
    {
        $user = $this->_em->find(self::TABLE, $user_id);

        if (!isset($user)) {
            throw new \Exception('User does not exist.');
        }

        if ($avatar['size'] == 0) {
            throw new \Exception('Cannot retrieve file size. Please, try another one.');
        }
        $fileExt = pathinfo($avatar['name'], PATHINFO_EXTENSION);
        $fileName = $user_id . substr(md5(time()), 0, 6) . '.' . $fileExt;
        $avatarsDir = dirname(APPLICATION_PATH) . '/public/avatars/';
        if (!move_uploaded_file($avatar['tmp_name'], $avatarsDir . $fileName)) {
            throw new \Exception("Couldn't write the file {$fileName}");
        }

        $this->resize($avatarsDir . $fileName, self::MAX_AVATAR_WIDTH, self::MAX_AVATAR_HEIGHT);

        $user->setAvatar("/avatars/{$fileName}");
        $this->_em->persist($user);
        $this->_em->flush();
        return $user;
    }

    public static function resize($file, $width, $height = null)
    {
        if (!extension_loaded('imagick')) {
            throw new \Exception('Image magick is not installed.');
        }
        $dirName = dirname($file);
        if (!is_writable($dirName)) {
            throw new \Exception("{$dirName} is not writable.");
        }

        $image = new \Imagick();
        $image->readimage($file);
        $imageWidth = $image->getImageWidth();
        if ($imageWidth > $width) {
            $image->thumbnailimage($width, null, 0);
        }

        $imageHeight = $image->getImageHeight();
        if (isset($height) && ($imageHeight > $height)) {
            $image->thumbnailimage(null, $height, 0);
        }

        $image->writeimage($file);
    }

    public function sendInvite($user_id, $hash, $email)
    {
        $user = $this->_em->find(self::TABLE, $user_id);

        $word = sprintf('%s|%s', $user->getId(), $hash);

        $message = $this->getInviteMessage($user->getNick(), $word);

        Mail::sendEmail($message, $email, 'Your friend invites you to TreasureAce.ca.');
    }

    private function getInviteMessage($nick, $word)
    {
        $baseUrl = \Zend_Registry::get('config')->resources->frontController->baseUrl;
        $url = $baseUrl . "register/$word";

        $message = <<<_END
        Hello.
        Your friend {$nick} wants to invite you.
        If you want to have fun, join the competition by visiting this url and registering:
        <a href="{$url}">{$url}</a>
_END;
        return $message;

    }


}
